#include "mylib.h"

#if HAVE_HASHLIST_H

struct hash_list *hash_create(unsigned int mode, 
							unsigned int size, 
							hash_count_cp count_cp,
							hash_compare_cp compare_cp,
							hash_copy_key_cp copy_key_cp,
							hash_copy_value_cp copy_value_cp)
{
	if (size == 0)
		return NULL;
	struct hash_list *pst;
	pst = malloc(sizeof(struct hash_list));
	if (pst == NULL)
		return NULL;
	pst->mode = mode;
	pst->table_size = size;
	pst->ppstHash_table = (struct hash_list_entry **)calloc(size, sizeof(struct hash_list_entry *));
	if (pst->ppstHash_table == NULL)
		goto err2;
	/*
	pst->pstOp = (struct hash_list_operation *)malloc(sizeof(struct hash_list_operation));
	if (pst->pstOp == NULL)
		goto err1;
	*/
	
	//memcpy(pst->pstOp, pstAttr, sizeof(struct hash_list_operation));
	pst->fun_count = count_cp;
	pst->fun_compare = compare_cp;
	pst->fun_copy_key = copy_key_cp;
	pst->fun_copy_value = copy_value_cp;
	Pthread_rwlock_init(&pst->lock, NULL);
	return pst;
	free(pst->ppstHash_table);
err2:
	free(pst);
	return NULL;
}

static struct hash_list_entry *hash_create_entry(struct hash_list *self, void *key, void *value)
{
	struct hash_list_entry *pst;
	hash_copy_key_cp ck;
	hash_copy_value_cp cv;
	if (self == NULL || key == NULL || value == NULL)
		return NULL;
	ck = self->fun_copy_key;
	cv = self->fun_copy_value;

	pst = Calloc(1, sizeof(struct hash_list_entry));
	pst->key = ck ? (*ck)(key) : key;
	pst->value = cv ? (*cv)(value) : value;
	return pst;
}

void *hash_search_list(struct hash_list *self, void *key)
{
	unsigned long index;
	void *pValue;
	struct hash_list_entry *pstEntry;
	Pthread_rwlock_rdlock(&self->lock);
	index = abs((*self->fun_count)(key)) % self->table_size;
	pstEntry = self->ppstHash_table[index];
	while(pstEntry && (*self->fun_compare)(pstEntry->key, key))
		pstEntry = pstEntry->pstList;
	if (pstEntry == NULL)
	{
		Pthread_rwlock_unlock(&self->lock);
		return NULL;
	}
	pValue = pstEntry->value;	//be protected by rw_lock
	Pthread_rwlock_unlock(&self->lock);
	return pValue;
}

struct hash_list_entry *hash_insert_list(struct hash_list *self, void *key, void *value)
{
	unsigned long index;
	struct hash_list_entry **ppstInsert;
	struct hash_list_entry *pstEntry;
	if ((pstEntry = hash_create_entry(self, key, value)) == NULL)
		return NULL;
	index = (*self->fun_count)(key);
	index = abs(index) % self->table_size;
	//index = abs((*self->pstOp->fun_count)(key)) % self->table_size;
	Pthread_rwlock_wrlock(&self->lock);
	ppstInsert = &self->ppstHash_table[index];
	while(*ppstInsert != NULL)
		ppstInsert = &(*ppstInsert)->pstList;
	
	*ppstInsert = pstEntry;
	
	self->element_size++;
	Pthread_rwlock_unlock(&self->lock);
	return pstEntry;
}

int hash_del_entry(struct hash_list *self, void *key)
{
	struct hash_list_entry **ppstDel;
	struct hash_list_entry *pstDel;
	unsigned long index;
	index = abs((*self->fun_count)(key)) % self->table_size;
	Pthread_rwlock_wrlock(&self->lock);
	ppstDel = &self->ppstHash_table[index];
	while(*ppstDel && (*self->fun_compare)((*ppstDel)->key, key))
	{
		ppstDel = &(*ppstDel)->pstList;
	}
	if (*ppstDel == NULL)
	{
		Pthread_rwlock_unlock(&self->lock);
		return -1;
	}
	pstDel = *ppstDel;
	*ppstDel = (*ppstDel)->pstList;
	free(pstDel);
	self->element_size--;
	Pthread_rwlock_unlock(&self->lock);
	return 0;
}

int hash_destroy(struct hash_list *self)
{
	int i;
	struct hash_list_entry *pstEntry, *pos, *pnext;
	/*
	struct hash_list_entry *pstEntry;
	struct hash_list_entry **ppstStack;
	struct hash_list_entry **ppstStackTop;
	Pthread_rwlock_wrlock(&self->lock);
	ppstStackTop = ppstStack = Malloc(self->element_size * sizeof(struct hash_list_entry *));
	for (i=0; i<self->table_size; i++)
	{
		pstEntry = self->ppstHash_table[i];
		while(pstEntry)
		{
			*ppstStack = pstEntry;
			ppstStack++;
			pstEntry = pstEntry->pstList;
		}
	}
	
	do
	{
		ppstStack--;
		free(*ppstStack);		
	}
	while(ppstStack != ppstStackTop);

	free(ppstStackTop);
	*/
	Pthread_rwlock_wrlock(&self->lock);
	for (i=0; i<self->table_size; i++)
	{
		pstEntry = self->ppstHash_table[i];
		if (pstEntry == NULL)
			continue;
		for (pos=pstEntry; pos!=NULL ;pos=pnext)
		{
			pnext = pos->pstList;
			free(pos);	
		}
	}
	Pthread_rwlock_unlock(&self->lock);
	Pthread_rwlock_destroy(&self->lock);
	free(self->ppstHash_table);
	//free(self->pstOp);
	free(self);
	return 0;
}

#endif

